package br.cnpq.webflowah.ontologia;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
//import java.util.Vector;

import org.mindswap.owl.OWLClass;
import org.mindswap.owl.OWLDataProperty;
import org.mindswap.owl.OWLIndividual;
import org.mindswap.owl.OWLIndividualList;
import org.mindswap.owl.OWLKnowledgeBase;
import org.mindswap.owl.OWLOntology;
import org.mindswap.owls.process.Condition;
import org.mindswap.owls.process.Process;
import org.mindswap.owls.process.Input;
import org.mindswap.owls.process.Output;
import org.mindswap.owls.process.Result;
import org.mindswap.owls.service.Service;
import org.mindswap.utils.URIUtils;

import br.cnpq.webflowah.beans.Conceito;
import br.cnpq.webflowah.beans.ServicoSemantico;

import com.hp.hpl.jena.ontology.DatatypeProperty;
import com.hp.hpl.jena.ontology.OntModel;
import com.hp.hpl.jena.ontology.Restriction;
import com.hp.hpl.jena.rdf.model.Resource;
import com.hp.hpl.jena.vocabulary.XSD;

public class ServicoOWL {

	public final static String OWL_URL = "http://localhost/webflowah/1.0/servicos.owl";
	
	public final static String OWL_URI = OWL_URL + "#";

	public final static String OWL_CLASS = OWL_URI + "Servico";
	
	public final static String OWL_PROPERTY_NOME = OWL_URI + "nome";
	
	public final static String OWL_PROPERTY_CATEGORIA = OWL_URI + "categoria";
	
	public final static String OWL_PROPERTY_ONTOLOGIA = OWL_URI + "ontologia";

	public final static String OWL_FILE = Repositorio.CACHE_DIR + "servicos.owl";
	
	private static OWLOntology ontology = null;
		
	// cria o arquivo caso nao exista 
	static {
		File file = new File(OWL_FILE);
		if (!file.exists()) criar();
		else abrir();
	}
			
	private static void criar() {
		try {
			OWLKnowledgeBase kb = Repositorio.getInstance();
			ontology = kb.createOntology(URI.create(OWL_URL), URI.create(OWL_URL));			
			ontology.createClass(URI.create(OWL_CLASS));
			ontology.createDataProperty(URI.create(OWL_PROPERTY_NOME));
			ontology.createDataProperty(URI.create(OWL_PROPERTY_CATEGORIA));
			ontology.createDataProperty(URI.create(OWL_PROPERTY_ONTOLOGIA));
			
			OntModel ontModel = (OntModel) ontology.getImplementation();
			DatatypeProperty property = ontModel.getDatatypeProperty(OWL_PROPERTY_NOME);
			property.addDomain(ontModel.getResource(OWL_CLASS));
			property.addRange(XSD.xstring);
			
			Restriction restriction = ontModel.createRestriction(property);
			restriction.convertToCardinalityRestriction(1);
			restriction.addSubClass(ontModel.getResource(OWL_CLASS));

			property = ontModel.getDatatypeProperty(OWL_PROPERTY_CATEGORIA);
			property.addDomain(ontModel.getResource(OWL_CLASS));
			property.addRange(XSD.xstring);
			
			restriction = ontModel.createRestriction(property);
			restriction.convertToCardinalityRestriction(1);
			restriction.addSubClass(ontModel.getResource(OWL_CLASS));
			
			property = ontModel.getDatatypeProperty(OWL_PROPERTY_ONTOLOGIA);
			property.addDomain(ontModel.getResource(OWL_CLASS));
			property.addRange(XSD.xstring);
			
			restriction = ontModel.createRestriction(property);
			restriction.convertToCardinalityRestriction(1);
			restriction.addSubClass(ontModel.getResource(OWL_CLASS));

			File file = new File(OWL_FILE);
			kb.getReader().getCache().addCachedFile(ontology.getURI().toString(), file);
			kb.getReader().getCache().updateIndexFile();
			
			commit();
			
			kb.unload(ontology);
		} catch (Exception e) {
			e.printStackTrace();			
		}
	}
	
	private static void abrir() {
		try {
			OWLKnowledgeBase kb = Repositorio.getInstance();
			ontology = kb.read(URI.create(OWL_URI)); 
			kb.unload(ontology);
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		}		
	}
	
//	public static Operacao recuperarOperacao(URI uri) {
//		try {
//			OWLKnowledgeBase kb = Repositorio.getInstance();
//			String str = uri.toString();
//			OWLOntology ont = kb.read(str.substring(0, str.lastIndexOf("#")));
//			Process process = ont.getProcess(uri);
//
//			Operacao operacao = new Operacao();
//			operacao.setProcess(process);
//			
//			Iterator iter = process.getInputs().iterator();
//			while (iter.hasNext()) {
//				Input input = (Input) iter.next();
//				operacao.addInput(input.getLocalName(), input.getParamType());
//			}
//			
//			iter = process.getOutputs().iterator();
//			while (iter.hasNext()) {
//				Output output = (Output) iter.next();
//				operacao.addOutput(output.getLocalName(), output.getParamType());
//			}
//			
//			kb.unload(ont);
//
//			return operacao;
//		} catch (URISyntaxException e) {
//			e.printStackTrace();
//		} catch (FileNotFoundException e) {
//			e.printStackTrace();
//		}
//		
//		return null;
//	}
	
	public static boolean existir(String uri) {
		OWLKnowledgeBase kb = Repositorio.getInstance();
		OWLOntology ont = kb.load(ontology);
		boolean isTrue = ont.getIndividual(URI.create(uri)) != null;
		kb.unload(ont);
		return isTrue;
	}
		
	public static ServicoSemantico recuperar(String uri) {
		try {
			OWLKnowledgeBase kb = Repositorio.getInstance();
			OWLOntology ont = kb.load(ontology);
			OWLIndividual ind = ont.getIndividual(URI.create(uri));
			OWLDataProperty prop0 = ont.getDataProperty(URI.create(OWL_PROPERTY_NOME));
			OWLDataProperty prop1 = ont.getDataProperty(URI.create(OWL_PROPERTY_CATEGORIA));
			OWLDataProperty prop2 = ont.getDataProperty(URI.create(OWL_PROPERTY_ONTOLOGIA));
			ServicoSemantico servico = new ServicoSemantico();
			servico.setNome(ind.getProperty(prop0).getLexicalValue());
			servico.setCategoria(ind.getProperty(prop1).getLexicalValue());
			servico.setOntologia(ind.getProperty(prop2).getLexicalValue());
			servico.setURI(ind.getURI().toString());
			kb.unload(ont);
			
			kb = Repositorio.newInstance(true);
			ont = kb.read(uri.substring(0, uri.lastIndexOf("#")));
			Service service = ont.getService(URI.create(uri));			

			// recuperar o conceito tarefa
			Process process = service.getProcess();
			Conceito tarefa = ConceitoOWL.recuperar(process.getURI());
			if (tarefa.getTipo() == null) {
				Conceito tipo = new Conceito();
//				tipo.setObrigatorio(false);
				tipo.setTipo(ConceitoOWL.tarefa);
				if (service.getProfile().getServiceClassification() != null) {
					String nome = URIUtils.getLocalName(service.getProfile().getServiceClassification());
					tipo.setNome(nome);
					tipo.setURI(ConceitoOWL.OWL_URI + nome);
				} else {
					tipo = ConceitoOWL.tarefa;
				}
				tarefa.setTipo(tipo);
				if (service.getProfile().getServiceProduct() != null) {				
					Conceito associacao = new Conceito();
					String nome = URIUtils.getLocalName(service.getProfile().getServiceProduct());					
					associacao.setNome(nome);
					associacao.setURI(service.getProfile().getServiceProduct().toString());
					associacao.setTipo(new Conceito(nome, ConceitoOWL.OWL_URI + nome));
					associacao.getTipo().setTipo(ConceitoOWL.objeto);
					associacao.setPredicado(ConceitoOWL.OWL_PROPERTY_ENVOLVE);
					tarefa.addAssociacao(associacao);
				}
			}
			servico.addTarefa(tarefa);
			
			// recuperar os conceitos objetos
			Conceito associacao = new Conceito();
			associacao.setNome(tarefa.getNome());
			associacao.setURI(tarefa.getURI());
			associacao.setTipo(tarefa.getTipo());
			associacao.setPredicado(ConceitoOWL.OWL_PROPERTY_USADOPOR);			
			Iterator iter = service.getProfile().getInputs().iterator();
			while (iter.hasNext()) {
				Input input = (Input) iter.next();
				Conceito objeto = ConceitoOWL.recuperar(input.getURI());
				if (objeto.getTipo() == null) {
					Conceito tipo = new Conceito();
//					tipo.setObrigatorio(false);
					tipo.setTipo(ConceitoOWL.objeto);
					tipo.setAnotacao(input.getParamType().getURI().toString());
					if (input.getParamType().isDataType()) {
						tipo.setNome(input.getLocalName());
						tipo.setURI(ConceitoOWL.OWL_URI + input.getLocalName());
					} else {
						String nome = URIUtils.getLocalName(input.getParamType().getURI()); 
						tipo.setNome(nome);
						tipo.setURI(ConceitoOWL.OWL_URI + nome);
					}
					objeto.setTipo(tipo);
					objeto.addAssociacao(associacao);
				}
				servico.addObjeto(objeto);				
			}
			
			associacao = new Conceito();
			associacao.setNome(tarefa.getNome());
			associacao.setURI(tarefa.getURI());
			associacao.setTipo(tarefa.getTipo());
			associacao.setPredicado(ConceitoOWL.OWL_PROPERTY_CRIADOPOR);
			iter = service.getProfile().getOutputs().iterator();
			while (iter.hasNext()) {
				Output output = (Output) iter.next();
				Conceito objeto = ConceitoOWL.recuperar(output.getURI());
				if (objeto.getTipo() == null) {
					Conceito tipo = new Conceito();
//					tipo.setObrigatorio(false);
					tipo.setTipo(ConceitoOWL.objeto);
					tipo.setAnotacao(output.getParamType().getURI().toString());
					if (output.getParamType().isDataType()) {
						tipo.setNome(output.getLocalName());
						tipo.setURI(ConceitoOWL.OWL_URI + output.getLocalName());
					} else {
						String nome = URIUtils.getLocalName(output.getParamType().getURI()); 
						tipo.setNome(nome);
						tipo.setURI(ConceitoOWL.OWL_URI + nome);
					}
					objeto.setTipo(tipo);
					objeto.addAssociacao(associacao);
				}
				servico.addObjeto(objeto);
			}
			
			associacao = new Conceito();
			associacao.setNome(tarefa.getNome());
			associacao.setURI(tarefa.getURI());
			associacao.setTipo(tarefa.getTipo());
			associacao.setPredicado(ConceitoOWL.OWL_PROPERTY_EXIGIDOPOR);
			iter = service.getProfile().getConditions().iterator();
			while (iter.hasNext()) {
				Condition condition = (Condition) iter.next();
				Conceito objeto = ConceitoOWL.recuperar(condition.getURI());
				if (objeto.getTipo() == null) {
					Conceito tipo = new Conceito();
					tipo.setTipo(ConceitoOWL.objeto);
					tipo.setNome(condition.getLocalName());
					tipo.setURI(ConceitoOWL.OWL_URI + condition.getLocalName());
					objeto.setTipo(tipo);
					objeto.addAssociacao(associacao);
				}
				servico.addObjeto(objeto);
			}
			
			associacao = new Conceito();
			associacao.setNome(tarefa.getNome());
			associacao.setURI(tarefa.getURI());
			associacao.setTipo(tarefa.getTipo());
			associacao.setPredicado(ConceitoOWL.OWL_PROPERTY_GERADOPOR);
			iter = service.getProfile().getResults().iterator();
			while (iter.hasNext()) {
				Result result = (Result) iter.next();
				OWLIndividualList effects = result.getEffects();
				for (int i=0; effects != null && i < effects.size(); i++) {
					OWLIndividual effect = effects.individualAt(i);
					Conceito objeto = ConceitoOWL.recuperar(effect.getURI());
					if (objeto.getTipo() == null) {
						Conceito tipo = new Conceito();
						tipo.setTipo(ConceitoOWL.objeto);
						tipo.setNome(effect.getLocalName());
						tipo.setURI(ConceitoOWL.OWL_URI + effect.getLocalName());
						objeto.setTipo(tipo);
						objeto.addAssociacao(associacao);
					}
					servico.addObjeto(objeto);
				}
			}
									
//			List<URI> objetos = new ArrayList<URI>();
//			Iterator iter = service.getProfile().getInputs().iterator();
//			while (iter.hasNext()) {
//				Input input = (Input) iter.next();
//				objetos.add(input.getURI());
//			}
//			iter = service.getProfile().getOutputs().iterator();
//			while (iter.hasNext()) {
//				Output output = (Output) iter.next();
//				objetos.add(output.getURI());
//			}			
//			List<URI> tarefas = new ArrayList<URI>();
//			Process process = service.getProcess();
//			tarefas.add(process.getURI());
//			kb.unload(ont);
//
//			// carrega os conceitos do tipo Objeto
//			iter = objetos.iterator();
//			while (iter.hasNext()) {				
//				Object conceito = ConceitoOWL.recuperar((URI) iter.next());
//				ss.addObjeto(conceito);
//			}			
//			// carrega os conceitos do tipo Tarefa
//			iter = tarefas.iterator();
//			while (iter.hasNext()) {				
//				Object conceito = ConceitoOWL.recuperar((URI) iter.next());
//				ss.addTarefa(conceito);
//			}
					
			return servico;
		} catch (URISyntaxException e) {
			e.printStackTrace();
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		}
		
		return null;
	}
	
//	public static List recuperarEntradas(String uri) {
//		try {
//			List<Object> list = null;
//			OWLKnowledgeBase kb = Repositorio.getInstance();
//			OWLOntology ont = kb.read(uri.substring(0, uri.lastIndexOf("#")));
//			Process process = ont.getProcess(URI.create(uri));
//
//			List<URI> entradas = new ArrayList<URI>();
//			Iterator iter = process.getInputs().iterator();
//			while (iter.hasNext()) {
//				Input input = (Input) iter.next();
//				entradas.add(input.getURI());
//			}
//			kb.unload(ont);
//
//			// carrega os conceitos do tipo Objeto
//			iter = entradas.iterator();
//			while (iter.hasNext()) {
//				if  (list == null) list = new ArrayList<Object>();
//				Object conceito = ConceitoOWL.recuperarTipo((URI) iter.next());
//				list.add(conceito);
//			}
//			
//			return list;
//		} catch (URISyntaxException e) {
//			e.printStackTrace();
//		} catch (FileNotFoundException e) {
//			e.printStackTrace();
//		}
//
//		return null;
//	}
	
//	public static List recuperarSaidas(String uri) {
//		try {
//			List<Object> list = null;
//			OWLKnowledgeBase kb = Repositorio.getInstance();
//			OWLOntology ont = kb.read(uri.substring(0, uri.lastIndexOf("#")));
//			Process process = ont.getProcess(URI.create(uri));
//
//			List<URI> saidas = new ArrayList<URI>();
//			Iterator iter = process.getOutputs().iterator();
//			while (iter.hasNext()) {
//				Output input = (Output) iter.next();
//				saidas.add(input.getURI());
//			}
//			kb.unload(ont);
//
//			// carrega os conceitos do tipo Objeto
//			iter = saidas.iterator();
//			while (iter.hasNext()) {
//				if  (list == null) list = new ArrayList<Object>();
//				Object conceito = ConceitoOWL.recuperarTipo((URI) iter.next());
//				list.add(conceito);
//			}
//			
//			return list;
//		} catch (URISyntaxException e) {
//			e.printStackTrace();
//		} catch (FileNotFoundException e) {
//			e.printStackTrace();
//		}
//
//		return null;
//	}
	
//	public static List recuperarPrecondicoes(String uri) {
//		return null;
//	}
	
//	public static List recuperarPoscondicoes(String uri) {
//		return null;
//	}
					
	public static List recuperarTodos() {
		try {
//			List<Vector<String>> list = null;
			List<ServicoSemantico> list = null;
			OWLKnowledgeBase kb = Repositorio.getInstance();
//			OWLOntology ont = kb.read(URI.create(OWL_URI)); 
			OWLOntology ont = kb.load(ontology);
			OWLClass class0 = ont.getClass(URI.create(OWL_CLASS));
			OWLDataProperty prop0 = ont.getDataProperty(URI.create(OWL_PROPERTY_NOME));
			OWLDataProperty prop1 = ont.getDataProperty(URI.create(OWL_PROPERTY_CATEGORIA));
			OWLDataProperty prop2 = ont.getDataProperty(URI.create(OWL_PROPERTY_ONTOLOGIA));
			OWLIndividualList indList = class0.getInstances();
			
			for (int i = 0; indList != null && i < indList.size(); i++) {
//				if (list == null) list = new ArrayList<Vector<String>>();
				if (list == null) list = new ArrayList<ServicoSemantico>();
				OWLIndividual ind = (OWLIndividual) indList.get(i);
//				Vector<String> rowData = new Vector<String>();
//				rowData.add(ind.getProperty(prop0).getLexicalValue());
//				rowData.add(ind.getProperty(prop1).getLexicalValue());
//				rowData.add(ind.getProperty(prop2).getLexicalValue());
//				list.add(rowData);
				ServicoSemantico servico = new ServicoSemantico();
				servico.setNome(ind.getProperty(prop0).getLexicalValue());
				servico.setCategoria(ind.getProperty(prop1).getLexicalValue());
				servico.setOntologia(ind.getProperty(prop2).getLexicalValue());
				servico.setURI(ind.getURI().toString());
				list.add(servico);
			}

			kb.unload(ont);
					
			return list;
		} catch (Exception e) {
			e.printStackTrace();
		}

		return null;
	}
	
	public static void apagar(ServicoSemantico servico) {
		OWLKnowledgeBase kb = Repositorio.getInstance();
		OWLOntology ont = kb.load(ontology);
		OntModel ontModel = (OntModel) ont.getImplementation();

		Resource resource = ontModel.getResource(servico.getURI());
		resource.removeProperties();
				
		kb.unload(ont);
		
		// apagar a classificacao
		List objetos = servico.getObjetos();
		for (int i=0; objetos != null && i < objetos.size(); i++) {
			Conceito conceito = (Conceito) objetos.get(i);
			ConceitoOWL.apagar(conceito);
		}
		
		List tarefas = servico.getTarefas();
		for (int i=0; tarefas != null && i < tarefas.size(); i++) {
			Conceito conceito = (Conceito) tarefas.get(i);
			ConceitoOWL.apagar(conceito);			
		}
		
		ConceitoOWL.commit();
	}
	
	public static void salvar(ServicoSemantico servico) {
		OWLKnowledgeBase kb = Repositorio.getInstance();
		OWLOntology ont = kb.load(ontology);
		OWLClass class0 = ont.getClass(URI.create(OWL_CLASS));
		OWLDataProperty prop0 = ont.getDataProperty(URI.create(OWL_PROPERTY_NOME));
		OWLDataProperty prop1 = ont.getDataProperty(URI.create(OWL_PROPERTY_CATEGORIA));
		OWLDataProperty prop2 = ont.getDataProperty(URI.create(OWL_PROPERTY_ONTOLOGIA));

		OWLIndividual ind = ont.createInstance(class0, URI.create(servico.getURI()));
		ont.addProperty(ind, prop0, servico.getNome());
		ont.addProperty(ind, prop1, servico.getCategoria());
		ont.addProperty(ind, prop2, servico.getOntologia());		

		kb.unload(ont);
	}
	
	public static void commit() {
		try {
			File file = new File(OWL_FILE);
			FileOutputStream fos = new FileOutputStream(file);
			ontology.write(fos, ontology.getFileURI());
			fos.close();
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}		
	}
		
//	public static void salvarTodos(Vector vector) {
//		try {
//			OWLKnowledgeBase kb = Repositorio.getInstance();
//			OWLOntology ont = kb.createOntology(URI.create(OWL_URI), URI.create(OWL_URI));			
//			OWLClass class0 = ont.createClass(URI.create(OWL_CLASS));
//			OWLDataProperty prop0 = ont.createDataProperty(URI.create(OWL_PROPERTY_NOME));
//			OWLDataProperty prop1 = ont.createDataProperty(URI.create(OWL_PROPERTY_CATEGORIA));
//			OWLDataProperty prop2 = ont.createDataProperty(URI.create(OWL_PROPERTY_ONTOLOGIA));
//			
//			OntModel ontModel = (OntModel) ont.getImplementation();
//			DatatypeProperty property = ontModel.getDatatypeProperty(OWL_PROPERTY_NOME);
//			property.addDomain(ontModel.getResource(OWL_CLASS));
//			property.addRange(XSD.xstring);
//			
//			Restriction restriction = ontModel.createRestriction(property);
//			restriction.convertToCardinalityRestriction(1);
//			restriction.addSubClass(ontModel.getResource(OWL_CLASS));
//
//			property = ontModel.getDatatypeProperty(OWL_PROPERTY_CATEGORIA);
//			property.addDomain(ontModel.getResource(OWL_CLASS));
//			property.addRange(XSD.xstring);
//			
//			restriction = ontModel.createRestriction(property);
//			restriction.convertToCardinalityRestriction(1);
//			restriction.addSubClass(ontModel.getResource(OWL_CLASS));
//			
//			property = ontModel.getDatatypeProperty(OWL_PROPERTY_ONTOLOGIA);
//			property.addDomain(ontModel.getResource(OWL_CLASS));
//			property.addRange(XSD.xstring);
//			
//			restriction = ontModel.createRestriction(property);
//			restriction.convertToCardinalityRestriction(1);
//			restriction.addSubClass(ontModel.getResource(OWL_CLASS));			
//			
//			for (int i=0; vector != null && i < vector.size(); i++) {
//				Vector rowData = (Vector) vector.get(i);
//				String uri = "" + rowData.get(2) + "#" + rowData.get(0); 
//				OWLIndividual ind = ont.createInstance(class0, URI.create(uri));
//				ont.addProperty(ind, prop0, rowData.get(0));
//				ont.addProperty(ind, prop1, rowData.get(1));
//				ont.addProperty(ind, prop2, rowData.get(2));
//			}
//
//			File file = new File(OWL_FILE);
//			// armazena no service.idx
//			if (!file.exists()) {
//				kb.getReader().getCache().addCachedFile(ont.getURI().toString(), file);
//				kb.getReader().getCache().updateIndexFile();
//			}
//			FileOutputStream fos = new FileOutputStream(file);
//			ont.write(fos, ont.getFileURI());
//			fos.close();
//
//			kb.unload(ont);
//		} catch (FileNotFoundException e) {
//			e.printStackTrace();
//		} catch (IOException e) {
//			e.printStackTrace();
//		}
//	}
	
}
